<template>
    <div class="app-container system-role" v-loading="isLoading">
        <sib-table
            ref="sibTableRef"
            :search-config="searchConfig"
            :table-column="tableColumn"
            :request-config="requestConfig">
            <!-- 自定义插槽，插槽名称为对应列配置的 code -->
            <template #operate="{ row }">
                <el-button type="primary" v-hasPermi="['system:role:update']" link @click="handleEdit(row)">修改</el-button>
                <el-button type="primary" v-hasPermi="['system:permission:assign-role-menu']" link @click="handleMenuPermission(row)">菜单权限</el-button>
                <el-button type="primary" v-hasPermi="['system:permission:assign-role-data-scope']" link @click="handleDataPermission(row)">数据权限</el-button>
                <el-button type="danger" link v-hasPermi="['system:role:remove']" @click="handleDelete(row)">删除</el-button>
            </template>
            <!-- 自定义表单与列表之间的内容 -->
            <template #operation-container>
                <el-button type="primary" plain icon="Plus" v-hasPermi="['system:role:add']" @click="handleAdd">新增</el-button>
                <el-button type="warning" plain icon="Download" v-hasPermi="['system:role:export']" @click="handleExport">导出</el-button>
            </template>
        </sib-table>

        <el-dialog
            v-if="dialogConfig.visible"
            append-to-body
            draggable
            align-center
            v-model="dialogConfig.visible"
            :close-on-click-modal="false"
            :title="dialogConfig.title"
            :width="dialogConfig.width || '600px'">
            <sib-form
                class="role-dialog-form"
                v-bind="dialogConfig"
                @item-change="formItemChange"
                @reset="dialogConfig.visible = false"
                @submit="handleSubmit">
                <template #checkedKeys="{ form }">
                    <el-checkbox v-model="form.nodeExpand" @change="handleToogleExpand">展开/折叠</el-checkbox>
                    <el-checkbox v-model="form.nodeCheckAll" @change="handleToogleChecked">全选/全不选</el-checkbox>
                    <el-checkbox v-model="form.checkStrictly">父子联动</el-checkbox>
                    <sib-tree
                        ref="treeRef"
                        show-checkbox
                        default-expand-all
                        :check-strictly="!form.checkStrictly"
                        :data="treeData"
                        :selection="form.checkedKeys">
                    </sib-tree>
                </template>
            </sib-form>
        </el-dialog>
    </div>
</template>

<script>
import { ref, reactive, computed, inject } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import tools from '@/utils/tools';

const { createTreeByList } = tools;

export default {
    name: 'SystemRole',
    setup() {
        const $axios = inject('$axios');
        const isLoading = ref(false);
        const sibTableRef = ref(null);
        // 查询模块表单配置
        const searchConfig = reactive({
            showExpand: false,
            rowFieldSize: 5,
            fields: [
                {
                    label: '角色名称',
                    code: 'name',
                    type: 'text',
                    maxlength: 100,
                },
                {
                    label: '角色标识',
                    code: 'code',
                    type: 'text',
                    maxlength: 100,
                },
                {
                    label: '状态',
                    code: 'status',
                    type: 'select',
                    requestConfig: {
                        url: '/system/dict/data/type/common_status',
                        method: 'get',
                    },
                    options: [],
                },
                {
                    label: '创建时间',
                    code: 'createTime',
                    type: 'daterange',
                    startCode: 'beginTime',
                    endCode: 'endTime',
                    // valueFormat: 'x',
                },
            ],
        });
        // 表格表头配置
        const tableColumn = ref([
            {
                label: '角色名称',
                code: 'name',
                minWidth: 180,
            },
            {
                label: '角色类型',
                code: 'type',
                type: 'tag',
                formatRequestConfig: {
                    requestConfig: {
                        url: '/system/dict/data/type/system_role_type',
                        method: 'get',
                    },
                },
                tagType: ({ type }) => (String(type) === '0' ? 'warning' : 'danger'),
            },
            {
                label: '显示顺序',
                code: 'sort',
            },
            {
                label: '状态',
                code: 'status',
                type: 'tag',
                relateFieldCode: 'status',
                tagType: ({ status }) => (String(status) === '0' ? 'success' : 'danger'),
            },
            {
                label: '创建时间',
                code: 'createTime',
                type: 'timeStamp',
                format: 'YYYY-MM-DD hh:mm',
                minWidth: 160,
            },
            {
                label: '操作',
                code: 'operate',
                type: 'slot',
                minWidth: 150,
                fixed: 'right',
            },
        ]);
        // 列表查询接口配置
        const requestConfig = reactive({
            url: '/system/role/list',
            method: 'get',
            // 自定义传参
            customSearchParams: obj => {
                const params = {};
                Object.keys(obj).forEach(key => {
                    if ([0, false].includes(obj[key]) || obj[key]) params[key] = obj[key];
                });
                if (params.beginTime) params.beginTime = +new Date(`${params.beginTime} 00:00:00`);
                if (params.endTime) params.endTime = +new Date(`${params.endTime} 23:59:59`);
                params.createTime = (params.createTime || []).map((t, i) => `${t} ${(['00:00:00', '23:59:59'][i])}`);
                return params;
            },
        });

        // 新增、编辑等弹窗配置
        const dialogConfig = reactive({
            title: '',
            width: '600px',
            rowFieldSize: 1,
            resetText: '取消',
            // add/edit/data/menu
            type: 'add',
            visible: false,
            // 新增、编辑的表单项配置
            editFields: [
                {
                    label: '角色名称',
                    code: 'name',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                },
                {
                    label: '角色标识',
                    code: 'code',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                },
                {
                    label: '显示顺序',
                    code: 'sort',
                    type: 'number',
                    controlsPosition: 'right',
                    required: true,
                },
                {
                    label: '状态',
                    code: 'status',
                    type: 'radio',
                    requestConfig: {
                        url: '/system/dict/data/type/common_status',
                        method: 'get',
                    },
                    options: [],
                    value: '0',
                    required: true,
                },
                {
                    label: '备注',
                    code: 'remark',
                    type: 'textarea',
                    maxlength: 500,
                },
            ],
            // 数据权限的表单项配置
            dataPermissionFields: [
                {
                    label: '角色名称',
                    code: 'name',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                    disabled: true,
                },
                {
                    label: '角色标识',
                    code: 'code',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                    disabled: true,
                },
                {
                    label: '权限范围',
                    code: 'dataScope',
                    type: 'select',
                    requestConfig: {
                        url: '/system/dict/data/type/system_data_scope',
                        method: 'get',
                    },
                    options: [],
                    value: '1',
                    required: true,
                },
                {
                    label: '权限范围',
                    code: 'checkedKeys',
                    type: 'slot',
                },
            ],
            // 菜单权限的表单项配置
            menuPermissionFields: [
                {
                    label: '角色名称',
                    code: 'name',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                    disabled: true,
                },
                {
                    label: '角色标识',
                    code: 'code',
                    type: 'text',
                    maxlength: 100,
                    required: true,
                    disabled: true,
                },
                {
                    label: '菜单权限',
                    code: 'checkedKeys',
                    type: 'slot',
                },
            ],
            fields: [],
            form: {},
        });
        const treeRef = ref(null);
        // 菜单数据
        const menus = ref([]);
        // 部门数据
        const depts = ref([]);
        const treeData = computed(() => ({ data: depts.value, menu: menus.value })[dialogConfig.type] || []);
        // 获取全部菜单
        $axios.get('/system/menu/list-all-simple').then(({ data }) => {
            menus.value = createTreeByList(data.data || []);
        });
        // 获取全部部门
        $axios.get('/system/dept/list-all-simple').then(({ data }) => {
            depts.value = createTreeByList(data.data || []);
        });


        return {
            treeRef,
            isLoading,
            sibTableRef,
            searchConfig,
            tableColumn,
            requestConfig,
            dialogConfig,
            treeData,
            handleAdd() {
                dialogConfig.type = 'add';
                dialogConfig.title = '新增角色';
                dialogConfig.fields = window.SIB.deepCopy(dialogConfig.editFields);
                dialogConfig.form = {};
                dialogConfig.visible = true;
            },
            handleEdit(row) {
                isLoading.value = true;
                $axios.get(`/system/role/get?id=${row.id}`).then(({ data }) => {
                    dialogConfig.type = 'edit';
                    dialogConfig.title = '编辑角色';
                    dialogConfig.fields = window.SIB.deepCopy(dialogConfig.editFields);
                    dialogConfig.form = data.data || row || {};
                    dialogConfig.visible = true;
                }).finally(() => {
                    isLoading.value = false;
                });
            },
            handleToogleExpand(checked) {
                menus.value.forEach(menu => {
                    treeRef.value.treeRef.store.nodesMap[menu.id].expanded = checked;
                });
            },
            handleToogleChecked(checked) {
                treeRef.value.setCheckedNodes(checked ? menus.value : []);
            },
            // 打开菜单权限弹窗
            handleMenuPermission({ id: roleId, name, code }) {
                isLoading.value = true;
                $axios.get(`/system/permission/list-role-menus?roleId=${roleId}`).then(({ data }) => {
                    const checkedKeys = data.data || [];
                    dialogConfig.type = 'menu';
                    dialogConfig.title = '设置菜单权限';
                    dialogConfig.fields = window.SIB.deepCopy(dialogConfig.menuPermissionFields);
                    dialogConfig.form = { roleId, name, code, checkedKeys, checkStrictly: true };
                    dialogConfig.visible = true;
                }).finally(() => {
                    isLoading.value = false;
                });
            },
            // 打开数据权限弹窗
            handleDataPermission({ dataScope, dataScopeDeptIds, name, code, id: roleId }) {
                dialogConfig.type = 'data';
                dialogConfig.title = '设置数据权限';
                const checkedKeys = dataScopeDeptIds || [];
                dialogConfig.fields = window.SIB.deepCopy(dialogConfig.dataPermissionFields);
                dialogConfig.form = { roleId, name, code, dataScope, checkedKeys, checkStrictly: true };
                const treeField = dialogConfig.fields.find(({ code }) => code === 'checkedKeys');
                treeField.show = String(dataScope) === '2';
                dialogConfig.visible = true;
            },
            formItemChange(data, field) {
                if (dialogConfig.type === 'data' && field.code == 'dataScope') {
                    const treeField = dialogConfig.fields.find(({ code }) => code === 'checkedKeys');
                    treeField.show = String(data.value) === '2';
                }
            },
            handleDelete(row) {
                ElMessageBox.confirm(`是否删除【${row.name}】`, '温馨提示').then(() => {
                    $axios.delete(`/system/role/delete?id=${row.roleId}`).then(() => {
                        ElMessage({ type: 'success', message: '删除成功' });
                        sibTableRef.value.getTableData();
                    });
                }).catch(() => {});
            },
            handleSubmit(form, cb) {
                let checkedKeys = [];
                if (treeRef.value) {
                    // 目前被选中的菜单节点
                    checkedKeys = treeRef.value.getCheckedKeys();
                    // 半选中的菜单节点
                    const halfCheckedKeys = treeRef.value.getHalfCheckedKeys();
                    checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
                }
                const requestObj = {
                    add: {
                        url: '/system/role/create',
                        method: 'post',
                        params: form,
                    },
                    edit: {
                        url: '/system/role/create',
                        method: 'put',
                        params: form,
                    },
                    data: {
                        url: '/system/permission/assign-role-data-scope',
                        method: 'put',
                        params: { ...form, dataScopeDeptIds: String(form.dataScope) === '2' ? checkedKeys : [] },
                    },
                    menu: {
                        url: '/system/permission/assign-role-menu',
                        method: 'put',
                        params: { ...form, menuIds: checkedKeys },
                    },
                };
                const { url, method, params } = requestObj[dialogConfig.type];
                $axios[method](url, params).then(() => {
                    dialogConfig.visible = false;
                    sibTableRef.value.getTableData();
                }).finally(cb);
            },
            handleExport() {
                isLoading.value = true;
                $axios({
                    url: '/system/role/export-excel',
                    params: sibTableRef.value.searchParams || {},
                    method: 'GET',
                    responseType: 'blob',
                }).then(res => {
                    window.SIB.download(res, `角色列表_${new Date().getTime()}.xlsx`);
                    ElMessage({ type: 'success', message: '导出成功' });
                }).finally(() => {
                    isLoading.value = false;
                });
            },
        };
    },
};
</script>

<style lang="scss">
.system-role {
    height: calc(100vh - 84px);

    .sib-table {
        height: 100%;
    }
}

.role-dialog-form {
    /* stylelint-disable-next-line selector-class-pattern */
    .sib-form-item__checkedKeys {
        .sib-tree {
            width: 100%;
            height: 200px;
            padding: 10px 0;
        }
    }
}
</style>
